iT邦幫忙

2023 iThome 鐵人賽

1
Modern Web

Super Easy CSS,極度簡單:寫出好的 CSS,從零開始前端生涯系列 第 37

#35 圖片的 1x, 2x, 3x 是什麼?關於網頁上圖片解析度的處理:HTML <img> srcset、CSS image-set() 與 @media resolution

  • 分享至 

  • xImage
  •  

↓ 今日學習重點 ↓

  • 了解向量圖、點陣圖是什麼?

  • 了解像素密度 (Pixel Density) 的原理

  • 使用 HTML <img> srcset 屬性處理圖片

  • 使用 CSS background-image image-set() 處理圖片

  • 使用 CSS @media resolution 處理圖片

為什麼我的圖片明明大小沒錯,在較好的螢幕上(例如 apple retina 螢幕)卻顯得糊糊的?

這些都是因為「像素密度 (Pixel Density) 」的緣故,我們在第 15 天的時候有稍微提過,只不過沒有深入探究,今天我們就來好好了解一下,並且學會 HTML 與 CSS 上的處理方法。

延伸閱讀:#15 網頁使用的單位大解析:px、rem、em、%、vw、vh (dvh, lvh, svh)、vmin、vmax


一、向量圖 vs. 點陣圖

向量圖 vs. 點陣圖

在開始優化圖片前,我們需要了解電腦中圖片檔案的基本知識。
圖片檔案分為 2 種,分別為向量圖與點陣圖。

1. 什麼是向量圖?

常見網頁檔案格式:svg
繪圖軟體檔案格式:espai

向量圖

向量圖片是由路徑組成,紀錄點與點之間的座標,如有曲線的話會使用貝茲曲線計算。在繪圖軟體中會有控制桿可以控制曲線的彎曲方式。

向量圖背後記錄的是各種點座標的數學運算,所以它放大縮小都不會失真,檔案大小通常也比較小,但缺點是比較難繪製出較細緻的筆觸或材質紋理等。

在網頁上,像 LOGO 與 icon 這種簡易的圖形通常都建議儲存為這種格式。

2. 什麼是點陣圖?

常見網頁檔案格式:
jpg (等同 jpeg)bmppng (可透明)、gif (可透明,可含動畫)、webp (可透明,可含動畫)、avif

點陣圖

螢幕的顯示是由很多格子組合起來的,在早期的螢幕上,眼睛湊很近看都能看到一格一格的格子,1 像素 (pixel) 就代表螢幕上的一個格子。

點陣圖片就是由像素組成,將圖片拉大就會看到許多由格子組成的色塊。照片或電腦繪圖因為有大量影像細節,難以用座標與數學運算紀錄,所以通常會儲存為點陣圖,使用許多像素色塊堆疊出整體樣貌。

點陣圖的缺點是當圖片的尺寸放大超過自己本身的大小時,會出現許多格子,明顯看到畫質不好。

BUT!我們開頭說過:
「明明大小沒錯,為何在較好的螢幕上(例如 apple retina 螢幕)卻顯得糊糊的?」

接下來,我們要來了解螢幕上的「像素密度 (Pixel Density) 」,就能解決這個問題了。


二、像素密度 (Pixel Density) :1x、2x 與 3x

隨著螢幕面板的科技發展,螢幕能顯示的畫面越來越好,除了顯色能力變好外,解析度也變高了。原本螢幕上的一個格子只能放 1 x 1 個像素(pixel),現在一個格子能夠放入 2 x 2 個,甚至是 3 x 3 個以上。

換言之,像素的密度變高了,所以呈現出來的畫面更細緻,舉個例子:

像素密度 (Pixel Density) :1x、2x 與 3x

在 App 與網頁設計中,為了不同「像素密度」會準備不同的圖檔,讓高解析度裝置的使用者下載高解析度的圖片,而低解析度裝置的使用者下載低的就好,這樣可以讓下載速度快一點,達到最佳體驗。

這些圖檔通常稱之為 1x、2x、3x 的圖檔,1x、2x、3x 是 dppx 這個單位的簡寫。目前常見的裝置解析度是 2x,最高能到達 4x。

延伸閱讀:
Resolution by iOS device — iOS Ref
重新認識 Pixel、DPI / PPI 以及像素密度 | INFOLINK Blog
现在手机分辨率这么大,如何写响应式布局? - 知乎


了解這點,我們就可以知道開頭的問題是為什麼發生了。

如果我在 2x 的螢幕上放了 1x 的圖,就會像下面這樣,顯得有點模糊,尤其是文字邊緣(不過這要使用 2x 以上的螢幕才看得出來):

如果想要知道自己的螢幕解析度是多少,可以開開看下面網友做的 Code Pen DEMO 連結:

連結:DPI check

關於螢幕像素密度的相關單位 ppidpidppx 的換算關係如下:

  1. ppi(Pixels Per Inch) = dpi(Dots Per Inch)

    • ppi 代表每英寸的「像素」數量。
      ppi = pixels / inch (對角線)

    • dpi 代表每英寸的「點」數量。
      在螢幕上「點」代表像素,所以等於 ppi,但是在印刷中由它的機械結構決定的。
      dpi = ppi = pixels / inch (對角線)

  2. dppx(Dots Per Pixel)

    • dppx 代表每 CSS 像素中包含的物理像素數量。
      dppx = pixels / CSS pixel

如果覺得算數很麻煩,沒關係。
在 CSS 中,我們只要知道 1x、2x、3x 的觀念,使用 dppx 這個單位就足夠了!


三、HTML/CSS 實作 DEMO

1. HTML <img> srcset

使用 HTML 的 <img> srcset 屬性就能很輕易地依據使用者裝置切換對應像素密度的圖片,不同密度的圖片使用逗號隔開,語法如下:

<img srcset="1x圖檔連結 1x,
			 2x圖檔連結 2x,
			 3x圖檔連結 3x">

DEMO:1x vs. Current dppx: HTML srcset

我發現使用這種方式,圖片比較容易被瀏覽器快取住(瀏覽器為了讓讀取速度快一點,存下之前載過的圖片,不重新再拿一次圖片),所以如果你使用雙螢幕測試,直接來回切換螢幕可能不會馬上變化。

延伸閱讀:[教學] 如何使用 img srcset 讓圖片在 RWD 網頁顯示適當解析度 - Shubo 的程式開發筆記


2. CSS background-imageimage-set()

還有一種方法,那就是 CSS 中 background-imageimage-set() ,詳細語法如下:

.img-set{
	background-image: image-set(
		url("1x圖檔連結") 1x,
		url("2x圖檔連結") 2x,
		url("3x圖檔連結") 3x);
}

DEMO:1x vs. Current dppx: CSS image-set()


3. CSS @media min-resolution / max-resolution

最後一種方式,是使用 CSS Media Queries 的新屬性:min-resolutionmax-resolution ,語法如下:

.img-set{
    @media screen and (min-resolution: 1x) {
        background-image: url("1x圖檔連結");
    }
    @media screen and (min-resolution: 2x) {
        background-image: url("2x圖檔連結");
    }
    @media screen and (min-resolution: 3x) {
        background-image: url("3x圖檔連結");
    }
}

DEMO:1x vs. Current dppx: CSS @media resolution

Media Queries 的 resolution 屬性,除了使用 1x、2x、3x 作為單位,也可以使用 dppxdpidpcm 作為單位。此外,除了運用在螢幕上,也可以運用在列印上。

延伸閱讀:resolution - CSS: Cascading Style Sheets | MDN

另外,還有一個寫法是 -webkit-device-pixel-ratio ,它也可以達到一樣的效果,但是它並非標準寫法,MDN 建議還是使用 resolution 的寫法。

延伸閱讀:-webkit-device-pixel-ratio - CSS:級聯樣式表 |MDN


四、DEBUG

1. 使用 JS 取得像素密度 (Pixel Density)

如果想要知道自己的螢幕解析度是多少,還可以使用 JS 取得當前裝置的 dppx,語法如下:

window.devicePixelRatio;

延伸閱讀:Window: devicePixelRatio property - Web APIs

最快的實測方式,就是打開瀏覽器的開發者模式,在 console 面板把這行打上去,以 Chrome 為例:


2. 使用開發者工具查看實際下載的圖片

如果想要知道網頁實際下載的是哪一張圖片,可以打開瀏覽器的開發者模式,切到 Network 頁籤,然後清除紀錄,再重新整理頁面(在重整按鈕上按右鍵可清除快取),觀察總共載入了哪些東西。


↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

如果你喜歡我的創作,還想看看其他有趣的分享與日常,
可以追蹤我的 IG @im1010ioio,或者是🧋送杯珍奶鼓勵我,謝謝你🥰。

Eva Chen 送杯珍奶鼓勵我


上一篇
#34 CSS 讓圖片填滿容器的各種方法,以圓形大頭貼為例:object-fit 與 background-size,搭配 aspect-ratio
系列文
Super Easy CSS,極度簡單:寫出好的 CSS,從零開始前端生涯37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言